package net.ib.mtalk.ui.attachment.emoticon;

import net.ib.mtalk.util.Dip;
import net.ib.mtalk.util.MTalkLogWriter;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.ImageView;

public class EmoticonGridAdapter extends BaseAdapter {

	/**
	 * 값이 할당되지 않았음을 나타냄.
	 */
	public static final int NONE = -1;
	
	private Context mContext;
	private EditText mTargetEditText = null;
	private int mPage = NONE;
	private GridView mMotherGridView = null;
	
	private int size = (int)Dip.toPixel(40);
	
	/**
	 * 이모티콘 순서가 유니코드 값의 순서를 따르는 어댑터를 생성한다.
	 * @param context 요청자의 문맥
	 */
	public EmoticonGridAdapter(Context context, GridView g, EditText targetEditText) {
		mContext = context;
		mMotherGridView = g;
		this.mTargetEditText = targetEditText;
	}
	
	/**
	 * 이모티콘 순서가 {@link RichString}에 정의된 페이지 테이블의 구성을 따르는 어댑터를 생성한다.
	 * @param context
	 * @param page 몇 번 페이지에 대한 어댑터인지. 유효하지 않은 값이면 세팅되지 않는다. 0-base number.
	 * @param g 
	 */
	public EmoticonGridAdapter(Context context, int page, GridView g, EditText targetEditText) {
		mContext = context;
		if (0 <= page && page < RichString.pageTable.length) {
			mPage = page;
		}
		mMotherGridView = g;
		this.mTargetEditText = targetEditText;
	}

	public int getCount() {
		if (mPage > NONE)
			return RichString.pageTable[mPage].length;
		return RichString.getResCount();
	}

	public Object getItem(int position) {
		if (mPage > NONE)
			return RichString.getResCodeAt(RichString.pageTable[mPage][position]);
		return RichString.getResCodeAt(position);
	}

	public long getItemId(int position) {
		if (mPage > NONE)
			return RichString.pageTable[mPage][position];
		return position;
	}
	
	/** 뷰 내용을 위한 데이터 캐시 */
	Bitmap[] bitmapHolder;

	@Override
	public View getView(final int position, View convertView, ViewGroup parent) {
		ImageView imageView;
		
		// 대상 뷰의 레퍼런스를 정함.
		if (convertView == null) {
			imageView = new ImageView(mContext);
			imageView.setLayoutParams(new GridView.LayoutParams(size, size));
			imageView.setAdjustViewBounds(false);
			imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
			imageView.setPadding(3, 3, 3, 3);
		} else {
			imageView = (ImageView) convertView;
		}

		// 대상이 되는 이미지의 리소스 ID를 판정
		int resCode = 0;
		if (mPage > NONE) {
			resCode = RichString.getResCodeAt(RichString.pageTable[mPage][position]);
		} else {
			resCode = RichString.getResCodeAt(position);
		}

		// 비트맵을 할당
		if (bitmapHolder == null) {
			bitmapHolder = new Bitmap[getCount()];
		}
		if (bitmapHolder[position] == null) {
			bitmapHolder[position] = BitmapFactory.decodeResource(mContext.getResources(), resCode);
		}
		imageView.setImageBitmap(bitmapHolder[position]);

		// 뷰 속성의 정의
		imageView.setClickable(true);
		imageView.setOnTouchListener(new OnTouchListener() {
			float memX = 0; float memY = 0;
			boolean onFling = false;

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				// 그리드뷰에 이벤트를 전달
				//mMotherGridView.onTouchEvent(event);

				switch(event.getAction()){
				case MotionEvent.ACTION_DOWN:
					onFling = false;
					memX = event.getRawX();
					memY = event.getRawY();
					break;
				case MotionEvent.ACTION_MOVE:
					if (Math.abs(event.getRawX()-memX) > Dip.toPixel(7)
							|| Math.abs(event.getRawY()-memY) > Dip.toPixel(7)) {
						// 변위의 허용 한계를 넘어버렸다면 처리하지 않는다. 이 경우 사용자가 드래그를 의도한 것으로 간주한다.
						onFling = true;
					}
					memX = event.getRawX();
					memY = event.getRawY();
					break;
				case MotionEvent.ACTION_UP:
				case MotionEvent.ACTION_CANCEL:
					if (Math.abs(event.getRawX()-memX) > Dip.toPixel(7)
							|| Math.abs(event.getRawY()-memY) > Dip.toPixel(7)) {
						// 변위의 허용 한계를 넘어버렸다면 처리하지 않는다. 이 경우 사용자가 드래그를 의도한 것으로 간주한다.
						onFling = true;
					}
					memX = event.getRawX();
					memY = event.getRawY();

					if (onFling) {
						onFling = false;
						return true; // 처리된 이벤트로 간주해버린다. 이 경우 onClick 효과는 발생하지 않는다.
					}
					
					if (mTargetEditText != null) {
						/* 이 블록의 코드가 이 자리에 있는 것은 괜히 그런 게 아니다.
						 * 
						 * 그리드에서 OnItemClick을 받는 것은 코드상 가장 직관적이지만, 동작하지 않았다.
						 * 어딘가에서 드래그와 터치 업 이벤트가 유실된다.
						 * OnItemClick 리스너를 사용할 수 있는 해법을 알 수 없었다.
						 * 
						 * 이미지 뷰에서 OnClick을 받으려고 할 경우, 간헐적으로 성공한다.
						 * 되는 경우가 어떤 조건인지 알 수 없었다.
						 * 
						 * 하지만 이 자리에는 안정적으로 도달하고 있다.
						 * OnClick에서 처리를 하든 여기서 처리를 하든 논리적으로는 같기 때문에,
						 * 보다 안정적인 쪽에 코드를 둔다.
						 * */
						RichString richString = new RichString(
								RichString.getStringCodeAt(RichString.pageTable[mPage][position]),
								(int)(mTargetEditText.getLineHeight()*1.2f));
						richString.insertInto(mTargetEditText);
					}
					break;
				}
				return false;
			}
		});

		return imageView;
	}
	
	/**
	 * @return 몇 번 이모티콘 페이지에 대한 어댑터인지. 세팅되지 않았다면 {@link EmoticonGridAdapter#NONE NONE}.
	 */
	public int getPage() {
		return mPage;
	}

	/**
	 * 이모티콘 크기를 지정해준다. 가로 세로 동일.
	 * @param size Pixel 단위의 크기.
	 */
	public void setSize(int size) {
		this.size = size;
	}

}
